import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_jl_bluetooth_plugin/model/jl_peripheral_model.dart';

enum JLOtaUpgradeState {
  preparing,
  prepared,
  upgrading,
  reconnect,
  success,
  failed,
  fileKeyError,
  fileError,
  readyToRestart,
  other,
}

typedef DeviceListUpdateCallback = void Function(
    List<JLPeripheralModel> deviceList, JLPeripheralState state);
typedef DeviceConnectCallback = void Function(JLPeripheralState state);
typedef OtaUpgradeProgressCallback = void Function(
    JLOtaUpgradeState state, double progress);
typedef ApplicationWillEnterForegroundCallback = void Function();

class FlutterJlBluetoothPlugin {
  /// ble设备列表
  static List<JLPeripheralModel>? deviceList;

  /// ble设备列表更新回调
  static DeviceListUpdateCallback? deviceListUpdateCallback;

  /// 设备连接回调
  static DeviceConnectCallback? deviceConnectCallback;

  /// ota升级进度回调
  static OtaUpgradeProgressCallback? otaUpgradeProgressCallback;

  /// 手机后台进前台
  static ApplicationWillEnterForegroundCallback? applicationWillEnterForegroundCallback;

  /// 工厂模式
  factory FlutterJlBluetoothPlugin() => _getInstance();

  static FlutterJlBluetoothPlugin get instance => _getInstance();
  static FlutterJlBluetoothPlugin? _instance;
  MethodChannel _methodChannel;
  EventChannel _eventChannel;

  FlutterJlBluetoothPlugin._internal(this._methodChannel, this._eventChannel) {
    _eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
  }

  static FlutterJlBluetoothPlugin _getInstance() {
    if (_instance == null) {
      MethodChannel methodChannel =
      MethodChannel('flutter_jl_bluetooth_plugin');
      EventChannel eventChannel =
      EventChannel('flutter_jl_bluetooth_plugin_event');
      _instance =
      new FlutterJlBluetoothPlugin._internal(methodChannel, eventChannel);
    }
    return _instance!;
  }

  Future<String> get test async {
    final String result = await _methodChannel.invokeMethod('test');
    return result;
  }

  /// 查询手机是否开启蓝牙
  Future<bool> get phoneBluetoothEnable async {
    final bool phoneBluetoothEnableResult =
    await _methodChannel.invokeMethod('JLPhoneBluetoothIsNotEnabled');
    return phoneBluetoothEnableResult;
  }

  /// 获取蓝牙设备是否连接
  Future<bool> get bleDeviceConnected async {
    final bool bleDeviceConnectedResult =
    await _methodChannel.invokeMethod('JLBleGetDeviceConnected');
    return bleDeviceConnectedResult;
  }

  /// 搜索蓝牙设备
  Future<void> startScanBleDevice() async {
    await _methodChannel.invokeMethod('JLBleStartScanDevice');
  }

  /// 设置蓝牙过滤
  Future<void> setBleFilter(bool enable) async {
    await _methodChannel.invokeMethod('JLBleSetFilter', {'enable': enable});
  }

  /// 获取蓝牙过滤信息
  Future<bool> get bleFilter async {
    final bool bleFilterResult =
    await _methodChannel.invokeMethod('JLBleGetFilter');
    return bleFilterResult;
  }

  /// 连接蓝牙设备
  Future<void> bleConnectToDevice({String identifier = '',
    String address = '',
    bool blePairEnable = false}) async {
    await _methodChannel.invokeMethod('JLBleDeviceRequireConnect', {
      'identifier': identifier,
      'address': address,
      'ble_pair_enable': blePairEnable
    });
  }

  /// 断开蓝牙设备
  Future<void> bleDisconnectToDevice() async {
    await _methodChannel.invokeMethod('JLBleDeviceRequireDisconnect');
  }

  /// 获取OTA升级文件数组
  Future<List> otaFileList(String docPath) async {
    final List otaFileListResult = await _methodChannel
        .invokeMethod('JLOTAGetFileList', {'OTAFileDocPath': docPath});
    return otaFileListResult;
  }

  /// 设置OTA升级文件路径
  Future<bool> setSelectOtaFilePath(String filePath) async {
    final bool setSelectOTAFilePathResult = await _methodChannel.invokeMethod(
        'JLOTASetSelectFilePath', {'selectOTAFilePath': filePath});
    return setSelectOTAFilePathResult;
  }

  /// 获取OTA升级文件路径
  Future<String> get selectOtaFilePath async {
    final dynamic otaFilePathResult =
    await _methodChannel.invokeMethod('JLOTAGetSelectFilePath');
    return otaFilePathResult ?? '';
  }

  /// 获取设备信息，并进行OTA升级
  Future<bool> getBleDeviceInfoAndStartOtaUpgrade() async {
    final bool getBleDeviceInfoAndStartOtaUpgradeResult = await _methodChannel
        .invokeMethod('JLOtaGetBleDeviceInfoAndStartOtaUpgrade');
    return getBleDeviceInfoAndStartOtaUpgradeResult;
  }

  /// 数据接收
  static void _onEvent(dynamic value) {
    if (value is Map) {
      // print("Map: $value");
      String eventName = value["EventName"];

      /// ble设备相关
      if (eventName == "JLBleUpdateDeviceListView") {
        /// 设备列表
        List eventObj = value["EventObject"];
        _handleUpdateListView(eventObj, JLPeripheralState.update);
      } else if (eventName == "JLBleDeviceConnected") {
        /// 设备连接
        dynamic eventObj = value["EventObject"];
        if (eventObj is List) {
          _handleUpdateListView(eventObj, JLPeripheralState.connected);
        } else {
          if (deviceConnectCallback != null) {
            deviceConnectCallback!(JLPeripheralState.connected);
          }
        }
      } else if (eventName == "JLBleDeviceDisconnected") {
        ///设备断开连接
        dynamic eventObj = value["EventObject"];
        if (eventObj is List) {
          _handleUpdateListView(eventObj, JLPeripheralState.disconnected);
        } else {
          if (deviceConnectCallback != null) {
            deviceConnectCallback!(JLPeripheralState.disconnected);
          }
        }
      } else if (eventName == "JLBleDeviceConnectRefuse") {
        if (deviceConnectCallback != null) {
          deviceConnectCallback!(JLPeripheralState.refuse);
        }
      }

      /// OTA升级相关
      if (eventName == "JLOtaUpgradePreparing" ||
          eventName == "JLOtaUpgrading") {
        Map eventObj = value["EventObject"];
        double progress = eventObj['progress'];
        JLOtaUpgradeState state = eventName == ""
            ? JLOtaUpgradeState.preparing
            : JLOtaUpgradeState.upgrading;
        if (deviceConnectCallback != null) {
          otaUpgradeProgressCallback!(state, progress);
        }
      } else if (eventName == "JLOtaUpgradePrepared" ||
          eventName == "JLOtaBleDeviceReconnect" ||
          eventName == "JLOtaUpgradeSuccess" ||
          eventName == "JLOtaUpgradeFailed" ||
          eventName == "JLOtaUpgradeFileKeyError" ||
          eventName == "JLOtaUpgradeFileError" ||
          eventName == "JLOtaBleDeviceReadyToRestart" ||
          eventName == "JLOtaUpgradeCloseOverTimeCheck") {
        JLOtaUpgradeState? state;
        switch (eventName) {
          case 'JLOtaUpgradePrepared':
            state = JLOtaUpgradeState.prepared;
            break;
          case 'JLOtaBleDeviceReconnect':
            state = JLOtaUpgradeState.reconnect;
            break;
          case 'JLOtaUpgradeSuccess':
            state = JLOtaUpgradeState.success;
            break;
          case 'JLOtaUpgradeFailed':
            state = JLOtaUpgradeState.failed;
            break;
          case 'JLOtaUpgradeFileKeyError':
            state = JLOtaUpgradeState.fileKeyError;
            break;
          case 'JLOtaUpgradeFileError':
            state = JLOtaUpgradeState.fileError;
            break;
          case 'JLOtaBleDeviceReadyToRestart':
            state = JLOtaUpgradeState.readyToRestart;
            break;
          default:
            state = JLOtaUpgradeState.other;
            break;
        }
        if (deviceConnectCallback != null) {
          otaUpgradeProgressCallback!(state, 0);
        }
      }

      /// 手机后台进前台
      if (eventName == "JLApplicationWillEnterForegroundNotification") {
        if (applicationWillEnterForegroundCallback != null) {
          applicationWillEnterForegroundCallback!();
        }
      }
    } else {
      print("_onEvent: $value");
    }
  }

  /// 处理设备数组
  static _handleUpdateListView(List list, JLPeripheralState state) {
    List<JLPeripheralModel> localDeviceList = [];
    for (int i = 0; i < list.length; i++) {
      Map jsonMap = list[i];
      JLPeripheralModel model = JLPeripheralModel.fromJson(jsonMap);
      localDeviceList.add(model);
    }
    deviceList = localDeviceList;
    if (deviceListUpdateCallback != null) {
      deviceListUpdateCallback!(deviceList!, state);
    }
  }

  /// 数据接收: 错误处理
  static void _onError(dynamic value) {
    print("flutter_jl_bluetooth_plugin_event _onError: $value");
  }
}
